package cn.yuanqiao.framework.web.service;

import java.util.concurrent.TimeUnit;

import cn.yuanqiao.archive.xiaoxitongzhi.service.IYqXxtzService;
import cn.yuanqiao.auth.service.SysRecordLogService;
import cn.yuanqiao.common.constant.Constants;
import cn.yuanqiao.common.constant.SecurityConstants;
import cn.yuanqiao.common.constant.SysContants;
import cn.yuanqiao.common.core.domain.model.LoginUser;
import cn.yuanqiao.common.exception.ServiceException;
import cn.yuanqiao.common.service.RedisService;
import cn.yuanqiao.common.utils.StringUtils;
import cn.yuanqiao.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import cn.yuanqiao.common.constant.CacheConstants;
import cn.yuanqiao.common.core.domain.entity.SysUser;
import cn.yuanqiao.common.core.redis.RedisCache;
import cn.yuanqiao.common.exception.user.UserPasswordNotMatchException;
import cn.yuanqiao.common.exception.user.UserPasswordRetryLimitExceedException;
import cn.yuanqiao.common.utils.SecurityUtils;
import cn.yuanqiao.framework.security.context.AuthenticationContextHolder;

/**
 * 登录密码方法
 * 
 * @author ruoyi
 */
@Component
public class SysPasswordService
{
    @Autowired
    private RedisCache redisCache;

    @Value(value = "${user.password.maxRetryCount}")
    private int maxRetryCount;

    @Value(value = "${user.password.lockTime}")
    private int lockTime;

    @Autowired
    private SysRecordLogService recordLogService;

    @Value("${encryption}")
    private String encryption;

    @Autowired
    private RedisService redisService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private IYqXxtzService archiveReleaseService;

    @Value("${regularlyChangingPws}")
    private Boolean regularlyChangingPws;

    /**
     * 登录账户密码错误次数缓存键名
     * 
     * @param username 用户名
     * @return 缓存键key
     */
    private String getCacheKey(String username)
    {
        return CacheConstants.PWD_ERR_CNT_KEY + username;
    }

    public void validate(SysUser user)
    {
        Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
        String username = usernamePasswordAuthenticationToken.getName();
        String password = usernamePasswordAuthenticationToken.getCredentials().toString();

        Integer retryCount = redisCache.getCacheObject(getCacheKey(username));

        if (retryCount == null)
        {
            retryCount = 0;
        }

        if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
        {
//            throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
            String errMsg = String.format("密码输入错误%s次，帐户锁定%s分钟", maxRetryCount, lockTime);
            if(regularlyChangingPws){
                errMsg = String.format("密码输入错误%s次，帐户已锁定", maxRetryCount, lockTime);
            }
            //添加日志
            recordLogService.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL,errMsg,user.getTenantCode());

            //添加信息
            if(!StringUtils.isEmpty(user.getTenantCode())){
                LoginUser sysadminUser = userService.getUserInfo("sysadmin",user.getTenantCode(), SecurityConstants.INNER).getData(); //消息创建人
                LoginUser sysssoUser = userService.getUserInfo("syssso",user.getTenantCode(),SecurityConstants.INNER).getData();  //消息接收人
                archiveReleaseService.addyqXxtzApi("账户："+user.getUserName()+"，"+errMsg,sysadminUser.getSysUser().getUserId(),sysssoUser.getSysUser().getUserId(),user.getTenantCode());

                //修改用户状态为锁定状态
                if(regularlyChangingPws){
                    SysUser sdUser = new SysUser();
                    sdUser.setUserId(user.getUserId());
                    sdUser.setStatus("1");
                    userService.changeStatusApi(sdUser);
                    //账户已锁定，清楚错误次数
                    redisService.deleteObject(getCacheKey(user.getUserName(),null==user.getTenantCode()||"".equals(user.getTenantCode())?"manager":"tenant",user.getTenantCode()));
                }
                throw new ServiceException(errMsg);
            }
        }

        if (!matches(user, password))
        {
            retryCount = retryCount + 1;
            redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
            throw new UserPasswordNotMatchException();
        }
        else
        {
            clearLoginRecordCache(username);
        }
    }

    public void validate(SysUser user, String password,String userType,String tenantCode)
    {
        String username = user.getUserName();

        Integer retryCount = redisCache.getCacheObject(getCacheKey(username,userType,user.getTenantCode()));

        if (retryCount == null)
        {
            retryCount = 0;
        }

        if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
        {
            String errMsg = String.format("密码输入错误%s次，帐户锁定%s分钟", maxRetryCount, lockTime);
            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL,errMsg,tenantCode);
            throw new ServiceException(errMsg);
        }

        if (!matches(user, password))
        {
            retryCount = retryCount + 1;
            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, String.format("密码输入错误%s次", retryCount),tenantCode);
            redisCache.setCacheObject(getCacheKey(username,userType,user.getTenantCode()), retryCount, lockTime, TimeUnit.MINUTES);
            throw new ServiceException("用户不存在/密码错误");
        }
        else
        {
            clearLoginRecordCache(username,userType,user.getTenantCode());
        }
    }

    public boolean matches(SysUser user, String rawPassword)
    {
        return SecurityUtils.matchesPassword(rawPassword, user.getPassword(), encryption);
    }

    public void clearLoginRecordCache(String loginName)
    {
        if (redisCache.hasKey(getCacheKey(loginName)))
        {
            redisCache.deleteObject(getCacheKey(loginName));
        }
    }

    public void clearLoginRecordCache(String loginName,String userType,String tenantCode)
    {
        if (redisCache.hasKey(getCacheKey(loginName,userType,tenantCode)))
        {
            redisCache.deleteObject(getCacheKey(loginName,userType,tenantCode));
        }
    }

    /**
     * 登录账户密码错误次数缓存键名
     *
     * @param username 用户名
     * @return 缓存键key
     */
    private String getCacheKey(String username,String userType,String tenantCode)
    {
        if(SysContants.MANAGEDEPTFLAG.equals(userType)){
            return CacheConstants.PWD_ERR_CNT_KEY + userType + ":" + username;
        }else{
            return CacheConstants.PWD_ERR_CNT_KEY + userType + ":" + tenantCode + ":"+ username;
        }
    }
}
